#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <cerrno>
#include <cstring>
#include <string>
#include <cstdlib>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

using namespace std;

#define PATH "/home"
#define PROJ_ID 66
#define SIZE 4096

class shm
{
public:
    shm()
        :_shmid(-1)
        ,_addr(nullptr)
    {}

    key_t getkey(const char* path = PATH, int proj_id = PROJ_ID)
    {   
        key_t key = ftok(path, proj_id);
        if(key < 0)
        {
            cout << "ftok error:" << errno << " reason:" << strerror(errno) << endl;
            exit(1);
        }

        cout << "getkey success:" << key << endl; 
        return key;
    }

    void create_shm(int size = SIZE, const char* path = PATH, int proj_id = PROJ_ID)
    {
        _shmid = shmget(getkey(path,proj_id),size,IPC_CREAT | IPC_EXCL);
        if(_shmid < 0)
        {
            cout << "shmget error:" << errno << " reason:" << strerror(errno) << endl;
            exit(2);
        }

        cout << "create_shm success" << endl;
    }

    int get_shm(int size = SIZE, const char* path = PATH, int proj_id = PROJ_ID)
    {
        _shmid = shmget(getkey(path,proj_id),size,IPC_CREAT);
        if(_shmid < 0)
        {
            cout << "get_shm error:" << errno << " reason:" << strerror(errno) << endl;
            exit(3);
        }    

        cout << "get_shm success" << endl;
        return _shmid;
    }

    bool shm_attach()
    {
        _addr = shmat(_shmid,nullptr,0);
        if(_addr == (void*)-1)
        {
            cout << "shmat error:" << errno << " reason:" << strerror(errno) << endl;
            return false;
        }

        cout << "shm_attach success" << endl;
        return true;
    }

    bool shm_detach()
    {
        int shmdt_return_val = shmdt(_addr);
        if(shmdt_return_val == -1)
        {
            cout << "shmdt error:" << errno << " reason:" << strerror(errno) << endl;
            return false;
        }

        cout << "shm_detach success" << endl;
        return true;
    }

    void close_shm()
    {
        int shmctl_return_val = shmctl(_shmid,IPC_RMID,nullptr);
        if(shmctl_return_val == -1)
        {
            cout << "close_shm error:" << errno << " reason:" << strerror(errno) << endl;
            exit(6);
        }

        cout << "close_shm success" << endl;
    }

    struct shmid_ds* get_imformation_of_shm()
    {
        static struct shmid_ds information;
        int num = shmctl(_shmid,IPC_STAT,&information);
        if(num == -1)
        {
            cout << "get_imformation_of_shm error:" << errno << " reason:" << strerror(errno) << endl;
            return nullptr;
        }

        cout << "get_imformation_of_shm success" << endl;
        return &information;
    }

    int get_shmid()
    {
        return _shmid;
    }

    void* get_addr()
    {
        return _addr;
    }

private:
    int _shmid;
    void* _addr;
};


#define Mode 0666
#define PIPEPath "./default"

class Fifo
{
public:
    Fifo(string path = PIPEPath, int mode = Mode)
        :_path(path)
        ,_mode(mode)
    {}

    void CreateNamePipe()
    {
        int return_mkfifo_val = mkfifo(_path.c_str(),_mode);
        if(return_mkfifo_val < 0)
        {
            cout << "mkfifo error:" << errno << " reason :" << strerror(errno) << endl;
            exit(1);
        }

        cout << "mkfifo success" << endl;
    }

    ~Fifo()
    {
        int return_unlink_val = unlink(_path.c_str());
        if(return_unlink_val < 0)
        {
            cout << "unlink error:" << errno << " reason :" << strerror(errno) << endl;
        }

        cout << "unlink namepipe success" << endl;
    }

private:
    string _path;
    int _mode;

};


class SyncLast
{
public:
    SyncLast()
        :wfd(-1)
        ,rfd(-1)
    {}

    void CreatePipe()
    {
        _fifo.CreateNamePipe();
    }

    void WOpen()
    {
        wfd = open(PIPEPath, O_WRONLY);
        if(wfd < 0)
        {
            cout << "wfd error" << endl;
            exit(7);
        }
            
    }

    void ROpen()
    {        
        rfd = open(PIPEPath, O_RDONLY);
        if(rfd < 0)
        {
            cout << "rfd error" << endl;
            exit(8);
        }    
    }

    bool Wait()
    {
        int wait = 0;
        ssize_t val = read(rfd, &wait, sizeof(wait));

        if(val == sizeof(wait))
        {
            cout << "wait success" << endl;
        }
        else if(val == 0)
        {
            cout << "wfd close, read finish->0, exit" << endl;
            return false;
        }
        else
        {
            cout << "read error" << endl;
            return false;
        }

        return true;
    }

    void Wake()
    {
        int wake = 0;
        ssize_t val = write(wfd, &wake, sizeof(wake));

        if(val != sizeof(wake))
        {
            cout << "write error" << endl;
            exit(10);
        }

        cout << "wake finish" << endl;
    }

    ~SyncLast()
    {
        close(wfd);
        close(rfd);
    }
private:
    Fifo _fifo;
    int wfd;
    int rfd;
};
